package com.cv.platform.service.uv;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cv.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cv.platform.controller.system.dashboard.vo.VideoTypeUvData;
import com.cv.platform.dal.dataobject.uv.CvVideoTypeUvDO;
import com.cv.platform.dal.mapper.uv.CvVideoTypeUvMapper;
import com.cv.system.api.dict.DictDataApi;
import com.cv.system.api.dict.dto.DictDataRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static com.cv.platform.dal.redis.RedisKeyConstants.DAILY_VIDEO_TYPE_UV;

/**
 * 视频类型播放统计业务层接口实现类
 *
 * @author Charles_XDXD
 */
@Service
@Slf4j
public class CvVideoTypeUvServiceImpl implements CvVideoTypeUvService {

    @Resource
    private CvVideoTypeUvMapper cvVideoTypeUvMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @DubboReference
    private DictDataApi dictDataApi;

    @Override
    public void syncDailyUv() {
        log.info("[CvVideoTypeUvServiceImpl.syncDailyUv]: 开始同步昨日视频类型播放统计数据");

        Collection<DictDataRespDTO> typeList = dictDataApi.getDictDataListByType("cv_video_types");
        LocalDate yesterday = LocalDate.now().minusDays(1);

        for (DictDataRespDTO type : typeList) {
            String key = String.format(DAILY_VIDEO_TYPE_UV, yesterday, type.getValue());
            Long uv = stringRedisTemplate.opsForValue().get(key) == null ? 0L : Integer.parseInt(stringRedisTemplate.opsForValue().get(key));
            CvVideoTypeUvDO cvVideoTypeUvDO = new CvVideoTypeUvDO();
            cvVideoTypeUvDO.setType(type.getValue());
            cvVideoTypeUvDO.setRecordDate(yesterday.atStartOfDay());
            cvVideoTypeUvDO.setUvCount(uv);
            cvVideoTypeUvMapper.insert(cvVideoTypeUvDO);
            stringRedisTemplate.delete(key);
        }

        log.info("[CvVideoTypeUvServiceImpl.syncDailyUv]: 昨日视频类型播放统计数据同步完毕，已清除缓存数据");
    }

    @Override
    public List<VideoTypeUvData> getVideoTypeUvData() {
        Collection<DictDataRespDTO> cvVideoTypes = dictDataApi.getDictDataListByType("cv_video_types");

        if (CollUtil.isEmpty(cvVideoTypes)) {
            return Collections.emptyList();
        }

        List<String> typeNameList = cvVideoTypes.stream().map(DictDataRespDTO::getLabel).toList();
        List<String> typeList = cvVideoTypes.stream().map(DictDataRespDTO::getValue).toList();

        // 生成上周所有日期（周一到周日）
        LocalDate start = LocalDate.now().minusWeeks(1).with(DayOfWeek.MONDAY);
        List<LocalDate> dateRange = IntStream.rangeClosed(0, 6)
                .mapToObj(start::plusDays)
                .toList();

        // 遍历类型查询对应视频数量
        List<VideoTypeUvData> result = new ArrayList<>();
        for (int i = 0; i < typeList.size(); i++) {
            String type = typeList.get(i);
            String typeName = typeNameList.get(i);

            LambdaQueryWrapper<CvVideoTypeUvDO> wrapper = new LambdaQueryWrapperX<CvVideoTypeUvDO>()
                    .between(CvVideoTypeUvDO::getRecordDate,
                            start.atStartOfDay(),
                            start.plusDays(6).atTime(LocalTime.MAX))
                    .eq(CvVideoTypeUvDO::getType, type)
                    .select(CvVideoTypeUvDO::getUvCount, CvVideoTypeUvDO::getRecordDate);

            Map<LocalDate, Long> uvMap = cvVideoTypeUvMapper.selectList(wrapper).stream().collect(Collectors.toMap(
                    d -> d.getRecordDate().toLocalDate(),
                    CvVideoTypeUvDO::getUvCount
            ));

            // 按日期顺序填充数据（缺失则补0）
            List<Long> collect = dateRange.stream()
                    .map(date -> uvMap.getOrDefault(date, 0L))
                    .toList();

            VideoTypeUvData videoTypeUvData = new VideoTypeUvData()
                    .setName(typeName)
                    .setData(collect);
            result.add(videoTypeUvData);
        }
        return result;
    }

}
